package tcpserver

import (
	"errors"
	"fmt"
	"net"
	"sync"
	"sync/atomic"
	"time"
	"util/log"
)

type TcpServer struct {
	lister      net.Listener
	callee      interface{}
	ip          string
	port        int
	maxclient   int
	connections int32
	connected   bool
	connlist    []Conn
	ll          sync.Mutex
	serial      int
	debug       bool
}

type servercaller interface {
	OnCreate(s *TcpServer)
}

func accept(server *TcpServer, id int) {
	for {
		conn, err := server.lister.Accept()
		if err != nil {
			break
		} else {
			go connHandler(server, conn)
		}
	}
}

//启动Listen
func (server *TcpServer) Start(threads int) error {
	if server.connected {
		return errors.New("tcpserver already started")
	}

	tcpAddr, err := net.ResolveTCPAddr("tcp", fmt.Sprint(server.ip, ":", server.port))
	if err != nil {
		return err
	} else {
		lister, err := net.Listen(tcpAddr.Network(), tcpAddr.String())
		if err != nil {
			return err
		} else {
			server.lister = lister
			server.connected = true
			for i := 0; i < threads; i++ {
				go accept(server, i)
			}

			log.TraceInfo("tcpserver", "start at ", lister.Addr().String())
		}
	}

	return nil
}

func (server *TcpServer) Debug(val bool) {
	server.debug = val
}

func (server *TcpServer) GetAddr() net.Addr {
	return server.lister.Addr()
}

func wait(server *TcpServer, ch chan bool) {
	for {
		if server.Count() == 0 {
			break
		}

		time.Sleep(10 * time.Millisecond)
	}

	ch <- true
}

//关闭Listen
func (server *TcpServer) Close(bwait bool) {
	if server.connected {
		server.closeAllConn()
		server.lister.Close()
		server.connected = false
		server.lister = nil
	}

	if bwait {
		ch := make(chan bool)
		go wait(server, ch)
		<-ch
	}

	server.callee = nil
	log.TraceInfo("tcpserver", "shutdown")
}

func (server *TcpServer) incCount() {
	atomic.AddInt32(&server.connections, 1)
}

func (server *TcpServer) decCount() {
	atomic.AddInt32(&server.connections, -1)
}

func (server *TcpServer) Count() int {
	return int(server.connections)
}

//关闭某个连接
func (server *TcpServer) closeConn(index int) {
	conn := server.lockConn(index)
	if conn == nil {
		return
	}
	defer server.unlockConn(index)

	conn.conn.Close()
	conn.active = false
	conn.conn = nil
	conn.serial = 0
	server.decCount()
}

//增加一个连接
func (server *TcpServer) addConn(conn net.Conn) int {
	server.ll.Lock()
	defer server.ll.Unlock()
	server.serial++
	if server.serial <= 0 {
		server.serial = 1
	}
	for i := 0; i < len(server.connlist); i++ {
		if !server.connlist[i].active {
			newconn := server.lockConn(i)
			if newconn == nil {
				continue
			}
			defer server.unlockConn(i)
			if newconn.conn != nil || newconn.active {
				continue
			}
			newconn.conn = conn
			newconn.serial = server.serial
			newconn.active = true
			server.incCount()
			return i
		}
	}

	return -1
}

func (server *TcpServer) lockConn(index int) *Conn {
	if index < 0 || index > len(server.connlist) {
		return nil
	}

	conn := &server.connlist[index]
	conn.lock.Lock()
	return conn
}

func (server *TcpServer) unlockConn(index int) {
	if index < 0 || index > len(server.connlist) {
		return
	}

	server.connlist[index].lock.Unlock()
}

//关闭所有连接
func (server *TcpServer) closeAllConn() {
	for idx := 0; idx < len(server.connlist); idx++ {
		conn := server.lockConn(idx)
		if conn == nil {
			continue
		}
		if conn.active {
			conn.conn.Close()
		}
		server.unlockConn(idx)
	}
}

func (server *TcpServer) Broadcast(data []byte, size int) {
	server.ll.Lock()
	defer server.ll.Unlock()

	for i := 0; i < len(server.connlist); i++ {
		if server.connlist[i].active {
			conn := server.lockConn(i)
			conn.Send(data, size)
			server.unlockConn(i)
		}
	}
}

//发送数据
func (server *TcpServer) Send(index int, serial int, data []byte, size int) error {
	if index < 0 || index > len(server.connlist) {
		return errors.New("index out of range")
	}

	conn := server.lockConn(index)
	if conn == nil {
		return errors.New("conn not found")
	}
	defer server.unlockConn(index)

	if conn.serial != serial {
		return errors.New("conn not found")
	}

	if data == nil || size <= 0 {
		return errors.New("data or size must above zero")
	}

	conn.Send(data, size)

	return nil
}

//关闭某个socket
func (server *TcpServer) CloseConn(index int, serial int) error {

	if index < 0 || index > len(server.connlist) {
		return errors.New("index out of range")
	}

	conn := server.lockConn(index)
	if conn == nil {
		return errors.New("conn not found")
	}
	defer server.unlockConn(index)

	if conn.serial != serial {
		return errors.New("conn not found")
	}

	if conn.conn == nil {
		return errors.New("conn closed")
	}
	conn.conn.Close()

	return nil
}

func CreateTcpServer(callee interface{}, ip string, port int, maxclient int) *TcpServer {

	tcpserver := &TcpServer{callee: callee, ip: ip, port: port, maxclient: maxclient}
	tcpserver.connlist = make([]Conn, maxclient, maxclient)

	for i := 0; i < maxclient; i++ {
		tcpserver.connlist[i].index = i
		tcpserver.connlist[i].bquit = make(chan bool)
		tcpserver.connlist[i].incoming = make(chan datapkg, 10)
	}

	caller, ok := tcpserver.callee.(servercaller)
	if ok {
		caller.OnCreate(tcpserver)
	}

	return tcpserver

}
